<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title>捆图</title>
    <style>
        body {
            background-color: #000000;
        }

        .node circle {
            stroke: black;
            stroke-width: 2px;
        }

        .node text {
            font-size: 12px;
            font-family: simsun;
        }

        .link {
            fill: none;
            stroke: white;
            stroke-opacity: .5;
            stroke-width: 8px;
        }
    </style>
    <script src="https://d3js.org/d3.v3.min.js"></script>
</head>

<body>
    <div id="main"></div>
    <script>
        var width = 1370; //SVG绘制区域的宽度
        var height = 670; //SVG绘制区域的高度
        var svg = d3.select("#main") //选择<div>
            .append("svg") //在<body>中添加<svg>
            .attr("width", width) //设定<svg>的宽度属性
            .attr("height", height); //设定<svg>的高度属性
        //1. 确定初始数据
        var vertex = {
            name: "",
            children: [{
                    name: "北京"
                }, {
                    name: "上海"
                }, {
                    name: "杭州"
                },
                {
                    name: "广州"
                }, {
                    name: "桂林"
                }, {
                    name: "昆明"
                },
                {
                    name: "成都"
                }, {
                    name: "西安"
                }, {
                    name: "太原"
                }
            ]
        };

        var edges = [{
                source: "北京",
                target: "上海"
            },
            {
                source: "北京",
                target: "广州"
            },
            {
                source: "北京",
                target: "杭州"
            },
            {
                source: "北京",
                target: "西安"
            },
            {
                source: "北京",
                target: "成都"
            },
            {
                source: "北京",
                target: "太原"
            },
            {
                source: "北京",
                target: "桂林"
            },
            {
                source: "北京",
                target: "昆明"
            },
            {
                source: "北京",
                target: "成都"
            },
            {
                source: "上海",
                target: "杭州"
            },
            {
                source: "昆明",
                target: "成都"
            },
            {
                source: "西安",
                target: "太原"
            }
        ];

        var Zoom_data = 400; //这个值可以调节图的大小
        //2. 转换数据
        var cluster = d3.layout.cluster()
            .size([360, width / 2 - Zoom_data])
            .separation(function (a, b) {
                return (a.parent == b.parent ? 1 : 2) / a.depth;
            });

        var bundle = d3.layout.bundle();

        //数据接口
        var nodes = cluster.nodes(vertex);
        var oLinks = map(nodes, edges);

        var links = bundle(oLinks);

        //将links中的source和target由名称替换成节点
        function map(nodes, links) {
            var hash = [];
            for (var i = 0; i < nodes.length; i++) {
                hash[nodes[i].name] = nodes[i];
            }
            var resultLinks = [];
            for (var j = 0; j < links.length; j++) {
                resultLinks.push({
                    source: hash[links[j].source],
                    target: hash[links[j].target]
                });
            }
            return resultLinks;
        }

        //3. 绘图
        var line = d3.svg.line.radial()
            .interpolate("bundle")
            .tension(.85)
            .radius(function (d) {
                return d.y;
            })
            .angle(function (d) {
                return d.x / 180 * Math.PI;
            });

        gBundle = svg.append("g")
            .attr("transform", "translate(" + (width / 2) + "," + (height / 2) + ")");

        var color = d3.scale.category20c();

        var link = gBundle.selectAll(".link")
            .data(links)
            .enter()
            .append("path")
            .attr("class", "link")
            .attr("d", line); //使用线段生成器


        var node = gBundle.selectAll(".node")
            .data(nodes.filter(function (d) {
                return !d.children;
            }))
            .enter()
            .append("g")
            .attr("class", "node")
            .attr("transform", function (d) {
                return "rotate(" + (d.x - 90) + ")translate(" + d.y + ")" + "rotate(" + (90 - d.x) + ")";
            });

        node.append("circle")
            .attr("r", 20)
            .style("fill", function (d, i) {
                return color(i);
            });

        node.append("text")
            .attr("dy", ".2em")
            .style("text-anchor", "middle")
            .text(function (d) {
                return d.name;
            });
    </script>

</body>

</html>